/*   Copyright 2008 Alex Radeski   Licensed under the Apache License, Version 2.0 (the "License");   you may not use this file except in compliance with the License.   You may obtain a copy of the License at       http://www.apache.org/licenses/LICENSE-2.0   Unless required by applicable law or agreed to in writing, software   distributed under the License is distributed on an "AS IS" BASIS,   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   See the License for the specific language governing permissions and   limitations under the License.*/package org.ezaero.bushel;import java.nio.ByteBufferimport java.util.jar.JarFile;
import java.util.List;
import groovy.xml.MarkupBuilder;import static ArtifactType.*;

public enum ArtifactType {    JAR, SRC, DOC;}

public class Bushel {        private final File outDir;        private final List<File> inDirs;        private final boolean verbose;        public Bushel(File outDir, List<File> inDirs, boolean verbose) {        this.outDir = outDir;        this.inDirs = inDirs;        this.verbose = verbose;    }    
    public Bushel(File outDir, File inDir) {        this.outDir = outDir;        this.inDirs = [ inDirs ];    }    
    def public run() {        run(this.outDir, this.inDirs);    }        def run(File outDir, List<File> inDirs) {
        def files = [];        inDirs.each { inDir -> inDir.eachFile { file -> if(file.name.endsWith(".jar")) files << file } }
                if(files.empty) {            println "No bundle jars found.";            return;        }        
        def bundles = new HashMap();
        
        files.each { 
            file -> 
            def manifest = new JarFile(file).manifest;
            def symbolicName = manifest.mainAttributes.getValue("Bundle-SymbolicName");
            def bundleVersion = manifest.mainAttributes.getValue("Bundle-Version");

            BundleInfo info = null;
            
            if(symbolicName == null || bundleVersion == null) {                file.name.eachMatch(/([_A-Za-z][\w_]+(\.[_A-Za-z][\w_]+)+)[_\-]((\d+\.\d+\.\d+)(\.(\w+)?))/, {                    symbolicName = it[1];                    bundleVersion = it[3];                });            }
            
            def bundleBaseName = symbolicName.split(/;/)[0];            def bundleArtifact = JAR;                        if(bundleBaseName.endsWith(".source")) {
                bundleBaseName = bundleBaseName.replace(".source", "");
                bundleArtifact = SRC;
            }             
            if(bundles[bundleBaseName] == null) { bundles[bundleBaseName] = new BundleInfo(); }             
            info = bundles[bundleBaseName]; 
            
            def importPackageDef = manifest.mainAttributes.getValue("Import-Package");
            if(importPackageDef != null) {
                importPackageDef.eachMatch(/([_A-Za-z][\w_]+(\.[\w_]+)+)/, { info.imports << it[0]})
            }
                
            def exportPackageDef = manifest.mainAttributes.getValue("Export-Package");
            if(exportPackageDef != null) {
                exportPackageDef.eachMatch(/([_A-Za-z][\w_]+(\.[\w_]+)+)/, { info.exports << it[0]})
            }

            def requireBundleDef = manifest.mainAttributes.getValue("Require-Bundle"); 
            if(requireBundleDef != null) {
                requireBundleDef.eachMatch(/([_A-Za-z][\w_]+(\.[\w_]+)+)/, { info.bundles << it[0]})
            }
            
            def verParts = bundleVersion.split(/\./);
            def orgParts = bundleBaseName.split(/\./);
                        if(bundleArtifact == JAR) { info.bin = file; }            else if(bundleArtifact == SRC) { info.src = file; }            
            info.org = (orgParts.length >= 2 ? "${orgParts[0]}.${orgParts[1]}" : "${orgParts[0]}");
            info.name = bundleBaseName;
            info.version = "${verParts[0]}.${verParts[1]}.${verParts[2]}";
            info.qualifier = (verParts.length == 4 ? "${verParts[3]}" : "");
        }
        
        if(verbose) println "Processing: ";                bundles.each { name, bundle ->            if(verbose) println "\t${bundle}";            
            def rootDir = new File(outDir, "${bundle.org}/${bundle.name}/");
            rootDir.mkdirs();
                        if(bundle.bin != null) {                def jarDir = new File(rootDir, "jars/");                jarDir.mkdirs();                def jarFile = new File(jarDir, "${bundle.name}-${bundle.fullVersion}.jar");                copy(bundle.bin, jarFile);            } 
            
            if(bundle.src != null) {                def srcDir = new File(rootDir, "srcs/");                srcDir.mkdirs();                def srcFile = new File(srcDir, "${bundle.name}.source-${bundle.fullVersion}.jar");                copy(bundle.src, srcFile);            }            
            def writer = new FileWriter("${rootDir}/ivy-${bundle.fullVersion}.xml");
            def xml = new MarkupBuilder(writer)
            xml.'ivy-module'(version:"1.0") {
                info(organisation:"${bundle.org}", module:"${bundle.name}", revision:"${bundle.fullVersion}", status:"release")                                configurations() {                    conf(name:"default", visibility:"public")                }                                publications() {
                    artifact(name:"${bundle.name}", type:"jar", ext:"jar")
                    if(bundle.src != null) { artifact(name:"${bundle.name}.source", type:"src", ext:"jar") }
                }
            }
            writer.close();
        }
    }
    
    def copy(src, dst) {
        def fis = new FileInputStream(src);
        def fos = new FileOutputStream(dst);
        fis.channel.transferTo(0, fis.channel.size(), fos.channel);                 fis.close();        fos.close();
    }
    
}
